﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.Ccr.Core;
using Microsoft.Ccr.Core.Arbiters;
using NUnit.Framework;
using XcoAppSpaces.Core.CcrWiring;
using XcoAppSpaces.Core;
using XcoAppSpaces.Core.CcrWiring.CcrRemote;
using XcoAppSpaces.Contracts.Messaging;

namespace test.XcoAppSpaces.Core.CcrWiring
{
	[TestFixture]
	public class testRemotableTask
	{
		class ConcreteRemotableTask : RemotableTask
		{
			public object LastExecutedWith { get; set; }

			public ConcreteRemotableTask(Handler<MessageToSend> messageProcessor, IPort assignedPort)
				: base(messageProcessor, "testAddress", "testService", Guid.Empty, assignedPort, MessageTransferMode.Parallel)
			{}

			public override ITask PartialClone()
			{
				return null;
			}

			protected override RemoteMessage CreateMessage(object value)
			{
				LastExecutedWith = value;
				return null;
			}

			public override RemotableTask PartialClone(IPort newAssignedPort, MessageTransferMode newMode)
			{
				return null;
			}
		}


		[Test]
		public void TestItemCount()
		{
			var task = new ConcreteRemotableTask(null, null);
			Assert.AreEqual(1, task.PortElementCount);
		}

		[Test]
		public void TestItemSetOk()
		{
			var task = new ConcreteRemotableTask(null, null);
			task[0] = new PortElement<int>(1);
		}

		[Test]
		[ExpectedException(typeof(ArgumentException))]
		public void TestItemSetError()
		{
			var task = new ConcreteRemotableTask(null, null);
			task[1] = new PortElement<int>(1);
		}

		[Test]
		public void TestItemGetOk()
		{
			var task = new ConcreteRemotableTask(null, null);
			var portElement = task[0];
		}

		[Test]
		[ExpectedException(typeof(ArgumentException))]
		public void TestItemGetError()
		{
			var task = new ConcreteRemotableTask(null, null);
			var portElement = task[1];
		}

		[Test]
		public void TestExecute()
		{
			var port = new Port<int>();
			MessageToSend executedMsg = null;
			var task = new ConcreteRemotableTask(msg => {executedMsg = msg;}, port);
			task[0] = new PortElement<int>(123);
			task.Execute();

			Assert.AreEqual(123, task.LastExecutedWith);
			Assert.IsNotNull(executedMsg);
			Assert.AreEqual("testAddress", executedMsg.RemoteAddress);
			Assert.AreEqual("testService", executedMsg.CommServiceName);
		}

		[Test]
		public void TestExecuteWithCausalities()
		{
			var port = new Port<int>();
			MessageToSend executedMsg = null;
			var task = new ConcreteRemotableTask(msg => { executedMsg = msg; }, port);
			task[0] = new PortElement<int>(123);
			var c = new Causality("c", new Port<Exception>(), new Port<string>());
			Dispatcher.AddCausality(c);
			task.Execute();
			Dispatcher.RemoveCausality(c);

			Assert.IsNotNull(executedMsg);
			Assert.AreEqual("testAddress", executedMsg.RemoteAddress);
			Assert.AreEqual("testService", executedMsg.CommServiceName);
			Assert.IsNotNull(executedMsg.Context);
			Assert.AreEqual(1, executedMsg.Context.Causalities.Length);
			Assert.AreEqual(c.Name, executedMsg.Context.Causalities[0].Name);
			Assert.AreEqual(c.ExceptionPort, executedMsg.Context.Causalities[0].ExceptionPort);
			Assert.AreEqual(c.CoordinationPort, executedMsg.Context.Causalities[0].CoordinationPort);
		}
	}
}
